#include "stm32f10x.h"                  // Device header


#define MPU_ADD   0xD0
#include "MPU_Reg.h"
//封装指定地址写和指定地址读的时序
//优化：在代码中，存在很多死循环的地方——超时退出

void CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT){
	uint32_t TimeOut;
	TimeOut=100;	
	while(I2C_CheckEvent(I2Cx, I2C_EVENT)!=SUCCESS){
			TimeOut--;
			if(TimeOut==0){
				break;//错误处理
			}
		}
}

void MPU_WriteReg(uint8_t RegAddress,uint8_t Data){
	//用此函数，则会一直传输数据，所以我们需要用标志位去确定它是否操作成功了，这里就要用EV5事件来确定
	I2C_GenerateSTART(I2C2, ENABLE);
	
	//while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);
	
	//封装
//		while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS){
//			TimeOut--;
//			if(TimeOut==0){
//				return;
//			}
//		}
	
	CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	
	//发送函数会自带应答位，所以我们不需要考虑应答，只需要考虑发送后的事件EV6即可
	I2C_Send7bitAddress(I2C2,MPU_ADD, I2C_Direction_Transmitter); 
	CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	//EV8_1的事件是提醒应该写入DR数据，不需要等待
	
	I2C_SendData(I2C2, RegAddress); //同理，等待对应的事件EV8
	CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING); 
	
	I2C_SendData(I2C2, Data);//当发送为最后一个数据时，就需要等待EV8_2事件
	CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTOP(I2C2, ENABLE); 

}

uint8_t MPU_ReadingReg(uint8_t RegAddress){
	uint8_t Data;
	I2C_GenerateSTART(I2C2, ENABLE);
	CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); 
	
	//发送函数会自带应答位，所以我们不需要考虑应答，只需要考虑发送后的事件EV6即可
	I2C_Send7bitAddress(I2C2,MPU_ADD, I2C_Direction_Transmitter); 
	CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); 
	//EV8_1的事件是提醒应该写入DR数据，不需要等待
	
	I2C_SendData(I2C2, RegAddress); //在最后一个数据，用EV8_2
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS); 
	
	I2C_GenerateSTART(I2C2, ENABLE);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS); 
	//主机接收
	I2C_Send7bitAddress(I2C2,MPU_ADD, I2C_Direction_Receiver); 
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS); 
	//接收从机的数据:规定：在接收数据之前，需要把ACK置0，同时设置停止位STOP
	//如果读取多个字节，那直接等待EV7事件，读取DR，就能收到数据，在接收最后一个字节之前EV7_1事件，需要把ACK置0，同时设置停止位STOP
	//如果读取一个字节，那在EV6事件之后，需要把ACK置0，同时设置停止位STOP，在等待EV7事件，不然会多一个字节
	I2C_AcknowledgeConfig(I2C2, DISABLE);
	I2C_GenerateSTOP(I2C2,ENABLE);
	while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS); 
	
	//读取DR
	Data=I2C_ReceiveData(I2C2); 
	I2C_AcknowledgeConfig(I2C2, ENABLE);  //应答值设为1，给从机应答，这样可以使指定地址收多个字节
	
	return Data;
	
}



void MPU6050_Init(void){
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Mode =I2C_Mode_I2C;  //I2C的模式
	I2C_InitStructure.I2C_ClockSpeed=50000;  //时钟频率，要低于400KHz
	I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;//时钟占空比，只有在时钟频率大于100KHz才有用，小于则固定的1：1;——能更快的传输
	I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;  //应答配置
	I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;  //STM做从机，可以被响应几位地址
	I2C_InitStructure.I2C_OwnAddress1=0x00;  //自身寄存器，当STM32做从机时，指定STM32的自身地址，方便主机呼叫
	I2C_Init(I2C2,&I2C_InitStructure);
	
	I2C_Cmd(I2C2,ENABLE);
	
	MPU_WriteReg(MPU6050_PWR_MGMT_1,0x01);  //解除睡眠,选择陀螺仪时钟
	MPU_WriteReg(MPU6050_PWR_MGMT_2,0x00);	//6个轴均不待机
	MPU_WriteReg(MPU6050_SMPLRT_DIV,0x09);	//采样分频为10
	MPU_WriteReg(MPU6050_CONFIG,0x06);	//滤波参数最大
	MPU_WriteReg(MPU6050_GYRO_CONFIG,0x18);	//陀螺仪和加速度选择最大
	MPU_WriteReg(MPU6050_ACCEL_CONFIG,0x18);
//	//此时的MPU就在进行大量的数据转换，数据存放在其他的寄存器里
}

void MPU_Getdata(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
      						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)  
{
	//读取加速度寄存器XYZ轴的高8位和低8位
	uint8_t DataH, DataL;								//定义数据高8位和低8位的变量
	
	DataH = MPU_ReadingReg(MPU6050_ACCEL_XOUT_H);		//读取加速度计X轴的高8位数据
	DataL = MPU_ReadingReg(MPU6050_ACCEL_XOUT_L);		//读取加速度计X轴的低8位数据
	*AccX = (DataH << 8) | DataL;						//数据拼接，通过输出参数返回
	
	DataH = MPU_ReadingReg(MPU6050_ACCEL_YOUT_H);		//读取加速度计Y轴的高8位数据
	DataL = MPU_ReadingReg(MPU6050_ACCEL_YOUT_L);		//读取加速度计Y轴的低8位数据
	*AccY = (DataH << 8) | DataL;						//数据拼接，通过输出参数返回
	
	DataH = MPU_ReadingReg(MPU6050_ACCEL_ZOUT_H);		//读取加速度计Z轴的高8位数据
	DataL = MPU_ReadingReg(MPU6050_ACCEL_ZOUT_L);		//读取加速度计Z轴的低8位数据
	*AccZ = (DataH << 8) | DataL;						//数据拼接，通过输出参数返回
	
	DataH = MPU_ReadingReg(MPU6050_GYRO_XOUT_H);		//读取陀螺仪X轴的高8位数据
	DataL = MPU_ReadingReg(MPU6050_GYRO_XOUT_L);		//读取陀螺仪X轴的低8位数据
	*GyroX = (DataH << 8) | DataL;						//数据拼接，通过输出参数返回
	
	DataH = MPU_ReadingReg(MPU6050_GYRO_YOUT_H);		//读取陀螺仪Y轴的高8位数据
	DataL = MPU_ReadingReg(MPU6050_GYRO_YOUT_L);		//读取陀螺仪Y轴的低8位数据
	*GyroY = (DataH << 8) | DataL;						//数据拼接，通过输出参数返回
	
	DataH = MPU_ReadingReg(MPU6050_GYRO_ZOUT_H);		//读取陀螺仪Z轴的高8位数据
	DataL = MPU_ReadingReg(MPU6050_GYRO_ZOUT_L);		//读取陀螺仪Z轴的低8位数据
	*GyroZ = (DataH << 8) | DataL;						//数据拼接，通过输出参数返回

	
}
